package admin.core.service;

import admin.core.mapper.BaseMapper;
import admin.core.page.Page;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;

public class ServiceImpl<M extends BaseMapper<E>, E> implements IService<E> {

    protected Class<E> entityClass = this.createEntityClass();
    protected Class<M> mapperClass = this.createMapperClass();

    protected M baseMapper;

    public ServiceImpl() {
        try {
            baseMapper = mapperClass.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public M getBaseMapper() {
        return baseMapper;
    }

    public void setBaseMapper(M baseMapper) {
        this.baseMapper = baseMapper;
    }

    public Class<E> getEntityClass() {
        return entityClass;
    }

    public void setEntityClass(Class<E> entityClass) {
        this.entityClass = entityClass;
    }

    public Class<M> getMapperClass() {
        return mapperClass;
    }

    public void setMapperClass(Class<M> mapperClass) {
        this.mapperClass = mapperClass;
    }

    private Class<M> createMapperClass() {
        try {
            return (Class<M>) Class.forName(parseTypeNames().get(0));
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    private Class<E> createEntityClass() {
        try {
            return (Class<E>) Class.forName(parseTypeNames().get(1));
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    private List<String> parseTypeNames() {
        Type genericSuperclass = this.getClass().getGenericSuperclass();
        Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
        if (actualTypeArguments.length < 2) {
            throw new RuntimeException("ServiceImpl does not specify two generic type.");
        }

        return Arrays.stream(actualTypeArguments).map(Type::getTypeName).toList();
    }

    @Override
    public int save(E entity) {
        return baseMapper.insert(entity);
    }

    @Override
    public int deleteById(Object id) {
        return baseMapper.deleteById(id);
    }

    @Override
    public int updateById(E entity) {
        return baseMapper.updateById(entity);
    }

    @Override
    public E getById(Object id) {
        return baseMapper.selectById(id);
    }


    @Override
    public Page<E> list(Integer pageNum, Integer pageSize) {
        Page<E> page = new Page<>(pageNum,pageSize);
        List<E> list = baseMapper.selectList(page.getPageNum(), page.getPageSize());
        List<E> all = baseMapper.selectList();
        page.setList(list);
        page.setTotal(all.size());
        return page;
    }

    @Override
    public Page<E> list(String text,Integer pageNum,Integer pageSize) {
        Page<E> page = new Page<>(pageNum,pageSize);
        List<E> list = baseMapper.selectList(text,page.getPageNum(), page.getPageSize());
        List<E> all = baseMapper.selectList(text);
        page.setList(list);
        page.setTotal(all.size());
        return page;

    }
}
